﻿// Copyright 2010 Maxime Serrano <lastchronicler@gmail.com>
// Copyright 2009, 2010 Matvei Stefarov <me@matvei.org>
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Net;
using System.Threading;

namespace ForgeCraft
{
    public static class WindowDB
    {
        public const string DBFile = "WindowDB.txt",
                            Header = "location,createdDate,windowType,ownerName,isPublic,allowedPlayers,inventory,additional(furnaceProperties)";

        public static ReaderWriterLockSlim locker = new ReaderWriterLockSlim();

        public static void Load(World world)
        {
            if (File.Exists(world.name + "\\" + DBFile))
            {
                locker.EnterWriteLock();
                try
                {
                    using (StreamReader reader = File.OpenText(world.name + "\\" + DBFile))
                    {
                        reader.ReadLine(); // header
                        while (!reader.EndOfStream)
                        {
                            string[] fields = reader.ReadLine().Split(',');
                            if (fields.Length == WindowInfo.fieldCount)
                            {
                                try
                                {
                                    WindowInfo info = new WindowInfo(fields);

                                    BlockPosition bp = new BlockPosition(int.Parse(info.location.Split(':')[0]), byte.Parse(info.location.Split(':')[1]), int.Parse(info.location.Split(':')[2]));

                                    Window win = null; 

                                    switch (info.windowType)
                                    {
                                        case 0:
                                            win = new ChestWindow(bp);
                                            break;
                                        case 1:
                                            win = new WorkBenchWindow(bp);
                                            break;
                                        case 2:
                                            win = new FurnaceWindow(bp);
                                            break;
                                        case 3:
                                            win = new DispenserWindow(bp);
                                            break;
                                    }

                                    info.WindowSet(win);

                                    if (!world.WindowList.ContainsKey(bp))
                                    {
                                        world.WindowList.Add(bp, win);
                                    }
                                    else
                                    {
                                        Logger.Log(world.name + "WindowDB.Load: Duplicate record for window \"{0} ({1})\" skipped.", LogType.Error, info.location, info.windowType);
                                    }
                                }
                                catch (FormatException ex)
                                {
                                    Logger.Log(world.name + "WindowDB.Load: Could not parse a record: {0}.", LogType.Error, ex.Message);
                                }
                                catch (IOException ex)
                                {
                                    Logger.Log(world.name + "WindowDB.Load: Error while trying to read from file: {0}.", LogType.Error, ex.Message);
                                }
                            }
                        }
                    }
                }
                finally
                {
                    locker.ExitWriteLock();
                }
                Logger.Log(world.name + "WindowDB.Load: Done loading Window DB ({0} records).", LogType.DBActivity, world.WindowList.Count);
            }
            else
            {
                Logger.Log(world.name + "WindowDB.Load: No DB file found.", LogType.Warning);
            }
        }

        public static void Save(World world)
        {
            Logger.Log(world.name + "WindowDB.Save: Saving window database ({0} records).", LogType.DBActivity, world.WindowList.Count);
            string tempFile = Path.GetTempFileName();
            locker.EnterReadLock();
            try
            {
                using (StreamWriter writer = File.CreateText(tempFile))
                {
                    writer.WriteLine(Header);

                    foreach (KeyValuePair<BlockPosition, Window> kvp in world.WindowList)
                    {
                        string[] list = new string[WindowInfo.fieldCount];

                        list[0] = kvp.Key.x + ":" + kvp.Key.y + ":" + kvp.Key.z;
                        list[1] = kvp.Value.createdDate.ToString();
                        list[2] = kvp.Value.Type.ToString();
                        list[3] = kvp.Value.ownerName;
                        list[4] = kvp.Value.isPublic.ToString();
                        list[5] = kvp.Value.allowedPlayers;

                        string invString = "";

                        for (short i = 0; i < kvp.Value.slots.Length; i++)
                        {
                            if (kvp.Value.slots[i].Type > 0)
                            {
                                invString += i + ":" + kvp.Value.slots[i].Type + ":" + kvp.Value.slots[i].Count + ":" + kvp.Value.slots[i].Damage + "|";
                            }
                        }

                        list[6] = invString;
                        list[7] = kvp.Value.additional;

                        WindowInfo entry = new WindowInfo(list);

                        writer.WriteLine(entry.Serialize());
                    }
                }
            }
            finally
            {
                locker.ExitReadLock();
            }
            try
            {
                File.Delete(world.name + "\\" + DBFile);
                File.Move(tempFile, world.name + "\\" + DBFile);
            }
            catch (Exception ex)
            {
                Logger.Log(world.name + "WindowDB.Save: An error occured while trying to save: " + ex, LogType.Error);
            }
        }
    }
}
